#pragma once
#include "TypeDefinitions.h"
#include  <string>
#include <iostream>
#include "ImageComparator.h"
#include "TriangleBuilder.h"
#include "Mutator.h"
#include <list>
#include <fstream>
#include <thread>
#include <future>

struct Solution{
	Solution(std::string inputName) :
		polygons(new Polygons()),
		fitness(0),
		mutator(TriangleBuilder(), &input, &image, &comparator),
		image(width, height, 1, channelsNumber, 0),
		input(inputName.c_str())
	{
		fitness = comparator.compare(&input, &image);
	}


	void compute()
	{
		while (!mutator.mutate(*polygons)){}

		//TODO dodac werjsciowy diff
		//fitness = mutator.fitnessDiff;
		// 
	/*	for(Polygons::iterator it = polygons->begin(); it != polygons->end(); it++)
		{
				image.draw_polygon(*(*it)->verticles, (*it)->color, (*it)->opacity);
		}
		fitness = comparator.compare(&image, &input);*/
		fitness += mutator.fitnessDiff;
	}
	
	Mutator mutator;
	Image image;
	Image input;
	Polygons* polygons;
	ImageComparator comparator;

	double fitness;
};

struct SolutionsSorter {
	bool operator() (Solution* i, Solution* j) { return (i->fitness > j->fitness);}
} solutionsSorter;



class Controller
{
public:
	Controller(std::string inputName, std::string output, int iterationNumber) :
		inputName_("input\\"+inputName),
		oputputName_(output),
		iterationNumber_(iterationNumber)
	{
		std::clock_t c_start = std::clock();
		
		srand (time(NULL));

		ImageComparator comparator;

		Image input(inputName_.c_str());
		Image image(width, height, 1, channelsNumber, 0);
		Image imageBig(width*2, height*2, 1, channelsNumber, 0);
		cimg_library::CImgDisplay disp(image,"result");
		cimg_library::CImgDisplay dispBig(imageBig,"big");



		typedef std::vector<Solution *> Solutions;
		Solutions solutions;
		const int populationSize = 8 ;

		for(int i = 0; i < populationSize; i++)
		{
			solutions.push_back(new Solution(inputName_));
		}

		Polygons* trianglesBest = new Polygons();

		double bestFit = 99999999999999999999999.0;
		double fitness = 99999999999999999999999.0;

		//for(int i = 0; i < iterationNumber; i++)
		while((std::clock() - c_start)/ CLOCKS_PER_SEC < 100)
		{
		/*	for(Solutions::iterator solution = solutions.begin(); solution != solutions.end(); ++solution)
			{
				(*solution)->compute();
			}*/

			std::vector<std::future<void> > futures;
			for(Solutions::iterator solution = solutions.begin(); solution != solutions.end(); ++solution)
			{
				futures.push_back(std::async(std::launch::async, &Solution::compute, *solution));
			}

			for(std::vector<std::future<void> >::iterator f = futures.begin(); f !=futures.end(); ++f)
			{
				f->get();
			}


			
			std::sort(solutions.begin(), solutions.end(), solutionsSorter);

			if ((solutions[populationSize-1])->fitness <= bestFit)
			{
				bestFit= (solutions[populationSize-1])->fitness;
				image.fill(0);

				for(Polygons::iterator it = (solutions[populationSize-1])->polygons->begin(); it < (solutions[populationSize-1])->polygons->end(); it++)
				{
					image.draw_polygon(*(*it)->verticles, (*it)->color, (*it)->opacity);
				}

				disp.display(image);

				

				for(Polygons::iterator it = trianglesBest->begin(); it<trianglesBest->end(); it++ )
				{
					delete (*it);
				}
				trianglesBest->clear();

				for(Polygons::iterator it = (solutions[populationSize-1])->polygons->begin(); it < (solutions[populationSize-1])->polygons->end(); it++)
				{
					trianglesBest->push_back((*it)->copy());
				}

				for(int i = 0; i < trianglesBest->size(); i++)
				{
					CPolygon* poly = (*trianglesBest)[i];
					for (int j = 0; j < poly->neighbours.size(); j++)
					{
						poly->neighbours[j] = (*trianglesBest)[poly->neighbours[j]->positionZ];
					}
				}


				/*

				for(Polygons::iterator it = trianglesBest->begin(); it != trianglesBest->end(); it++)
				{
					if ( *it )
					{
						image.draw_polygon(*(*it)->verticles, (*it)->color, (*it)->opacity);
					}
				}

				disp.display(image);

				*/
			}

			
			for(Solutions::iterator solution = solutions.begin(); solution != solutions.end(); ++solution)
			{
				for(Polygons::iterator polygon = (*solution)->polygons->begin(); polygon != (*solution)->polygons->end(); ++polygon )
				{
					delete (*polygon);
				}
				(*solution)->polygons->clear();

				for(Polygons::iterator it = trianglesBest->begin(); it<trianglesBest->end(); it++ )
				{
					(*solution)->polygons->push_back((*it)->copy());
				}

				for(int i = 0; i < (*solution)->polygons->size(); i++)
				{
					CPolygon* poly = (*(*solution)->polygons)[i];
					for (int j = 0; j < poly->neighbours.size(); j++)
					{
						poly->neighbours[j] = (*(*solution)->polygons)[poly->neighbours[j]->positionZ];
					}
				}

				(*solution)->fitness = bestFit;
			}
			


		}

	//	saveResults(&triangles);

		image.fill(0);
		int neighboursNumber = 0;
		int numberOfPoints = 0;
	/*	for(Polygons::iterator it = solutions[0]->polygons->begin(); it != solutions[0]->polygons->end(); it++)
		{
			if ( *it )
			{
				image.draw_polygon(*(*it)->verticles, (*it)->color, (*it)->opacity);
				neighboursNumber+= (*it)->neighbours.size();
				numberOfPoints +=(*it)->verticles->width();
			}
		}*/

		for(Polygons::iterator it = solutions[0]->polygons->begin(); it != solutions[0]->polygons->end(); it++)
		{
			if ( *it )
			{
				for(int i=0; i < (*it)->verticles->width(); ++i)
				{
					(*(*it)->verticles)(i,0) *=2; 
					(*(*it)->verticles)(i,1) *=2; 
				}
				imageBig.draw_polygon(*(*it)->verticles, (*it)->color, (*it)->opacity);
			}
		}
		dispBig.display(imageBig);

		std::cout<<"Diff: "<<comparator.compare(&input, &image)/78030000.0<<"%"<<std::endl;

		disp.display(image);
		system("PAUSE");
	}


	void saveResults(Polygons* triangles)
	{
		std::ofstream svg("picture.svg");
		svg<<"<?xml version=\"1.0\" standalone=\"no\"?>"<<std::endl;
		svg<<"<!DOCTYPE svg PUBLIC \"-\/\/W3C\/\/DTD SVG 1.1\/\/EN\" \"http:\/\/www.w3.org\/Graphics\/SVG\/1.1\/DTD\/svg11.dtd\">"<<std::endl;
		svg<<"<svg width=\"100%\" height=\"100%\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">"<<std::endl;
		svg<<"<polygon points=\"0,0, 200,0, 200,200, 0,200\" style=\"fill:rgb(0,0,0);stroke:none\"/>"<<std::endl;
		for(Polygons::iterator it = triangles->begin(); it<triangles->end(); it++)
		{
			svg<<(*it)->toSVG();
		}
		svg<<"</svg>"<<std::endl;

		svg.close();
	}

	std::string inputName_;
	std::string oputputName_;
	int iterationNumber_;
};

